
/*
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: GPL-3.0+
 * License-Filename: LICENSE
 *
 * few routines translated from c++ source from graphlet:
 * This software is distributed under the Lesser General Public License
 * (C) Universitaet Passau 1986-1991
 *
 * Linux Cookie:  551 of 1140
 * "You know, we've won awards for this crap."
 * -- David Letterman
 *
 * The software is licensed under the GNU General Public License, version 3.
 * It implies that the source code is available, and the license gives you the freedom
 * to study the code and modify it in any way that you see fit.
 * If you pass parts or all of the code, compiled parts of the code,
 * or a derived product on to others, you have to make the code available to them on the same conditions.
 */

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
#include <sys/types.h>

#include "splay-tree.h"
#include "main.h"
#include "lmain.h"
#include "nes.h"
#include "options.h"
#include "rhp.h"
#include "mem.h"
#include "folding.h"

/* default layout algorithm to use */
#define DEFAULT_ALGO "bary"

/* default pre-layout algorithm to use */
#define DEFAULT_PREALGO "none"

/* default node weight adjust to use */
#define DEFAULT_NODEWEIGHTADJUST "left"

/* number of levels in the drawing */
int number_of_layers = 0;

/* */
int number_of_nodes = 0;

/* */
int number_of_edges = 0;

/* algorithm to start with */
static const char *heuristic = DEFAULT_ALGO;

/* optional pre-processor for algorithm or "" for none */
static const char *preprocessor = DEFAULT_PREALGO;

/* node weight adjust in barycenter */
static const char *nodeweightadjust = DEFAULT_NODEWEIGHTADJUST;

/* crossings of drawing */
static int64_t current_initial_crossings = 0;
static int64_t current_crossings = 0;

/* (x,y) offset for drawing, extra space needed for arrows */
static int xoffset = 6;
static int yoffset = 6;

/* x-spreading factor of drawing range 0.5...5.0 step 0.1 default 1.0 */
double xspreading = 1.0;

/* y-spreading factor of drawing range 0.5...5.0 step 0.1
 * set to high value then hor. lines do not overlap much
 */
double yspreading = 1.5;

/* x placement style */
int xplace_mode = XPLACE_DEFAULT;

/* serial uniq number for nodes */
static int current_id = 0;

/* nodes-at-level tables */
static struct dln **nal = NULL;

/* nodes-at-level tables */
static struct dln **nal_end = NULL;

/* how many levels */
static int nal_nlevels = 0;

/* nodes-at-level number of nodes for every level */
static int *nal_count = NULL;

/* forward decl. */
static void nal_print(void);
static void nal_rebuild(void);
static void nal_clear(void);
static void layouter2draw_x0_centered(void);
static void layouter2draw_x0_followingi(void);
static void layouter2draw_x0_followingl(void);
static void layouter2draw_x0_followingr(void);
static void layouter2draw_x0_followingo(void);
static void layouter2draw_x0_left(void);
static void layouter2draw_y0(void);
static void calc_subgraph_area(void);
static int getnodedata_from_rhp_1(int num, int level, int pos, void *data);
static int getnodedata_from_rhp_2(int num, int level, int pos, void *data);
static void static_layouter2draw(void);
static void static_layouter2draw_pos(void);
static void static_parsed2layouter(void);
static void static_mainl_clear(void);

/* */
int get_begin_crossings(void)
{
	return (current_initial_crossings);
}

/* */
int get_end_crossings(void)
{
	return (current_crossings);
}

/* convert relative (x,y) into absolute positions */
void layouter2draw_pos(void)
{
	static_layouter2draw_pos();
	return;
}

/* */
void layouter2draw(void)
{
	static_layouter2draw();
	return;
}

/* entr (1) command can be used to launch relayout of a file when file changes on Linux.
 * there should be nodes in the graph to run this.
 */
void layout_graph(void)
{
	const char *aw = (char *)0;
	int iaw = 0;

	/* check node weight adjust mode */
	aw = get_adjustweight();

	if (strcmp(aw, "left") == 0) {
		iaw = 0;
	}

	if (strcmp(aw, "avg") == 0) {
		iaw = 1;
	}

	/* */
	current_initial_crossings = (int64_t) 0;
	current_crossings = (int64_t) 0;

	if (option_parsedebug || 0) {
		printf("%s(): running barycenter\n", __FUNCTION__);
		fflush(stdout);
	}

	/* */
	rhp_layout( /* options */ 0, /* 0 left node weight adjust or 1 avg. adjust */ iaw);
	/* */

	current_initial_crossings = rhp_initial_crossings();
	current_crossings = rhp_current_crossings();

	return;
}

/* */
void mainl_clear(void)
{
	static_mainl_clear();
	return;
}

/* */
void parsed2layouter(void)
{
	static_parsed2layouter();
	return;
}

/* */
void set_default_algo(void)
{
	return;
}

/* used in options.c, return 0 if not valid algo name */
char *is_valid_algo(char *algo)
{
	if (strcmp(algo, "bary") == 0) {
		return ((char *)"bary");
	}
	return ((char *)0);
}

/* used in options.c, return 0 if not valid algo name */
char *is_valid_prealgo(char *prealgo)
{
	if (strcmp(prealgo, "none") == 0) {
		return ((char *)"none");
	}
	return ((char *)0);
}

/* */
const char *get_heuristic(void)
{
	/* to implement */
	return ((const char *)heuristic);
}

/* */
const char *get_preprocessor(void)
{
	/* to implement */
	return ((const char *)preprocessor);
}

/* */
int set_heuristic(const char *name)
{
	/* to implement */
	if (strcmp(name, "bary") == 0) {
		heuristic = name;
	}
	return (0);
}

/* */
int set_preprocessor(const char *name)
{
	if (strcmp(name, "none") == 0) {
		preprocessor = name;
	}
	/* return 1 if it changed */
	return (0);
}

/* barycenter node adjust weight avg, left */
int set_adjustweight(const char *name)
{
	int changed = 0;
	/* */
	if (strcmp(name, nodeweightadjust) == 0) {
		/* did not change */
		changed = 0;
	} else {
		if (strcmp(name, "left") == 0) {
			nodeweightadjust = name;
			changed = 1;
		} else if (strcmp(name, "avg") == 0) {
			nodeweightadjust = name;
			changed = 1;
		} else {
			/* invalid name do not change */
			changed = 0;
		}
	}
	/* return 1 if it changed */
	return (changed);
}

/* barycenter node adjust weight avg, left */
const char *get_adjustweight(void)
{
	/* avg or left */
	return ((char *)nodeweightadjust);
}

/***test***/

struct priority_data {
	struct unode *node;
	int priority;
	int done;
};

static struct priority_data *nl = (struct priority_data *)0;

/* pos node delta */
static void static_layouter2draw_pos_centerm_mvnode(struct unode *un, int delta)
{
	int deltax = 0;

	deltax = delta;

	if (deltax == 0) {
		return;
	}

	if (option_placedebug || 0) {
		printf("%s(): moving node number=[n%d] \"%s\" %d pixels to x0=%d x1=%d\n", __FUNCTION__, un->number, un->name,
		       deltax, un->x0 + deltax, un->x1 + deltax);
	}

	un->x0 = un->x0 + deltax;
	un->x1 = un->x1 + deltax;

	return;
}

/* */
static void static_layouter2draw_pos_centerm_fixdummy2(int i)
{
	struct dli *lp = NULL;
	struct ddn *dnptr = NULL;
	int x1t = 0;
	int x1f = 0;
	struct unode *ufn = (struct unode *)0;

	/* get current layer */
	lp = dlip[i];

	if (lp == (struct dli *)0) {
		printf("%s(): expected level %d from %d levels\n", __FUNCTION__, i, dli_nlevels);
		return;
	}

	/* scan nodes in layer */
	dnptr = lp->nl;

	while (dnptr) {
		x1t = 0;
		x1f = 0;

		ufn = dnptr->dn->un;
		if (ufn->dout && ufn->din) {
			x1t = ufn->dout->tn->x1;
			x1f = ufn->din->fn->x1;

			ufn->x1 = ((x1f + x1t) / 2);
			ufn->x0 = ufn->x1;
		}
		dnptr = dnptr->next;
	}

	return;
}

/* fix dummy interleaved nodes */
static void static_layouter2draw_pos_centerm_fixdummy(void)
{
	int i = 0;

	/* update the dummy interleaved nodes at intermediate levels */
	for (i = dfsstartlevel + 1; i < dli_nlevels; i = i + 2) {
		static_layouter2draw_pos_centerm_fixdummy2( /* level */ i);
	}

	return;
}

/* */
static void static_layouter2draw_pos_centerm_fixo2( /* level */ int level)
{
	int md = 0;
	double dxspacing = 0.0;
	int nnodes = 0;
	int maxxl = 0;
	int minxl = 0;
	struct dli *lp = NULL;
	struct ddn *dnptr = NULL;
	int i = 0;
	int j = 0;
	int halfw = 0;
	struct unode *ufn = (struct unode *)0;
	struct unode *ufn0 = (struct unode *)0;

	/* spacing x dir */
	dxspacing = xspreading * option_xyspread;

	/* x spacing between the nodes */
	md = (int)dxspacing;

	nnodes = dlip[level]->nnodes;

	if (nnodes == 1) {
		/* only 1 node, nothing todo here */
		return;
	}

	nl = (struct priority_data *)mymalloc((nnodes * sizeof(struct priority_data)), __FUNCTION__, __LINE__);

	/* get current layer */
	lp = dlip[level];

	/* scan nodes in layer */
	dnptr = lp->nl;

	i = 0;

	/* */
	while (dnptr) {
		nl[i].node = dnptr->dn->un;

		if (i == 0) {
			maxxl = nl[i].node->x0 + nl[i].node->bbx + md;
			minxl = nl[i].node->x0;
		} else {
			if (nl[i].node->x0 + nl[i].node->bbx + md > maxxl) {
				maxxl = nl[i].node->x0 + nl[i].node->bbx + md;
			}
			if (nl[i].node->x0 < minxl) {
				minxl = nl[i].node->x0;
			}
		}

		i++;

		dnptr = dnptr->next;
	}

	/* get middle of drawing */
	halfw = (maxxl - minxl) / 2;

	/* get current layer */
	lp = dlip[level];

	/* scan nodes in layer */
	dnptr = lp->nl;

	i = 0;

	/* mark which nodes are on left or right part of drawing */
	while (dnptr) {
		nl[i].node = dnptr->dn->un;

		if (nl[i].node->x0 > halfw) {
			/* at right part of drawing */
			nl[i].done = 1;
		} else {
			/* node is at left part of drawing */
			nl[i].done = 0;
		}
		i++;

		dnptr = dnptr->next;
	}

	for (i = 0; i < nnodes; i++) {
		ufn = nl[i].node;
		if (i == (nnodes - 1)) {
			/* most right node */
			if (ufn->x0 < (nl[i - 1].node->x0 + nl[i - 1].node->bbx + md)) {
				/* to right */
				static_layouter2draw_pos_centerm_mvnode(ufn,
									(nl[i - 1].node->x0 + nl[i - 1].node->bbx + md) - ufn->x0);
			}
		} else if (i == 0) {
			/* most left node */
			if ((ufn->x0 + ufn->bbx + md) > nl[i + 1].node->x0) {
				/* to left */
				static_layouter2draw_pos_centerm_mvnode(ufn, -((ufn->x0 + ufn->bbx + md) - nl[i + 1].node->x0));
			}
		} else {
			/* mid node */
			if (((ufn->x0 + ufn->bbx + md) > nl[i + 1].node->x0)
			    || (ufn->x0 < (nl[i - 1].node->x0 + nl[i - i].node->bbx + md))) {
				/* node is at right or left part of drawing */
				if (nl[i].done == 0) {
					/* node is at left part of drawing and move node left */
					j = i;
					do {
						ufn0 = nl[j].node;
						if (ufn0->x0 < (nl[j - 1].node->x0 + nl[j - 1].node->bbx + md)) {
							static_layouter2draw_pos_centerm_mvnode(nl[j - 1].node,
												(ufn0->x0 -
												 (nl[j - 1].node->x0 +
												  nl[j - 1].node->bbx + md)));
						}
						j--;
					}
					while (j > 0);
				} else {
					/* node is at right part of drawing and move node right if needed */
					j = i;
					do {
						ufn0 = nl[j].node;
						if ((ufn0->x0 + ufn0->bbx + md) > nl[j + 1].node->x0) {
							static_layouter2draw_pos_centerm_mvnode(nl[j + 1].node,
												(nl[j + 1].node->x0 -
												 (ufn0->x0 + ufn0->bbx + md)));
						}
						j++;
					}
					while (j < nnodes - 1);
				}
			}
		}
	}

	myfree((void *)nl, __FUNCTION__, __LINE__);
	nl = (struct priority_data *)0;

	return;
}

/* fix overlap nodes */
static void static_layouter2draw_pos_centerm_fixo(void)
{
	int i = 0;

	/* update */
	for (i = dfsstartlevel; i < dli_nlevels; i = i + 2) {
		static_layouter2draw_pos_centerm_fixo2( /* level */ i);
	}

	return;
}

/* */
static int static_layouter2draw_pos_centerm_lower_connectivity(struct unode *un)
{
	return (un->outdegree);
/*  return (un->indegree); */
}

/* */
static int static_layouter2draw_pos_centerm_upper_connectivity(struct unode *un)
{
	return (un->indegree);
/*  return (un->outdegree); */
}

/* follow edge incoming edges until a real node */
static struct uedge *static_layouter2draw_pos_prioup_fei(struct uedge *ue)
{
	struct uedge *ue2 = (struct uedge *)0;
	struct unode *tn1 = (struct unode *)0;

	if (option_placedebug || 0) {
		printf("%s(): scanning \"%s\"->\"%s\" rev=%d horedge=%d\n", __FUNCTION__, ue->fn->name, ue->tn->name,
		       ue->bitflags.reversed, ue->bitflags.horedge);
		tn1 = ue->tn;
		printf("%s(): follow edge is dout=%p din=%p\n", __FUNCTION__, (void *)tn1->dout, (void *)tn1->din);
	}

	if (option_feprio == 0) {
		return (ue);
	}

	/* edge to check */
	ue2 = ue;

	/* do not do horizontal edges, they are on same level */
	if (ue2->bitflags.horedge) {
		return (ue2);
	}

	/* keep scanning */
	while (ue2) {

		if (option_placedebug || 0) {
			printf("%s(): scanning \"%s\"->\"%s\" rev=%d horedge=%d\n", __FUNCTION__, ue2->fn->name, ue2->tn->name,
			       ue2->bitflags.reversed, ue2->bitflags.horedge);
		}

		/* accept edgelabel as real */
		if (ue2->fn->bitflags.dummynode == 0) {
			break;
		}

		/* take incoming edge from dummy node */
		ue2 = ue2->fn->din;

		if (ue2 == (struct uedge *)0) {
			/* shouldnothappen */
			printf("%s(): nil ue2\n", __FUNCTION__);
			break;
		}

	}

	if (ue2 == (struct uedge *)0) {
		printf("%s(): did not find edge ue2\n", __FUNCTION__);
		/* safety return, the original edge */
		return ((struct uedge *)ue);
	}

	return ((struct uedge *)ue2);
}

/* */
static int static_layouter2draw_pos_centerm_upper_barycenter(struct unode *node)
{
	int result = 0;
	splay_tree usepoe = (splay_tree) 0;
	splay_tree_node spn = (splay_tree_node) 0;
	struct uedge *ue = (struct uedge *)0;
	struct uedge *etemp = (struct uedge *)0;
	struct uedge *etemp2 = (struct uedge *)0;
	double dresult = 0.0;
	int nc = 0;

	/* edges connected to this node */
	usepoe = node->sp_poe;

	spn = splay_tree_min(usepoe);

	result = 0;

	/* scan the edges connected to this node */
	while (spn) {

		/* this edge is connected to node ufn */
		ue = (struct uedge *)spn->value;

		/* incoming edges */
		if (ue->tn == node) {

			/* skip hor. edges */
			if (ue->bitflags.horedge) {
				spn = splay_tree_successor(usepoe, spn->key);
				continue;
			}

			etemp = ue->fn->din;
			etemp2 = etemp;

			if (etemp) {

				if (option_placedebug || 0) {
					printf("%s(): incoming edge \"%s\"->\"%s\" at node \"%s\" is \"%s\"->\"%s\"->\"%s\"\n",
					       __FUNCTION__, etemp->fn->name, etemp->tn->name, ue->fn->name, etemp->fn->name,
					       etemp->tn->name, ue->fn->name);
				}

				/* search edge if target is not a real node */
				if ((etemp->fn->bitflags.dummynode == 1) || (etemp->fn->bitflags.edgelabel == 1)
				    || (ue->fn->bitflags.dummynode)) {

					/* scan connected edges, always return a valid etemp2 */
					etemp2 = static_layouter2draw_pos_prioup_fei(etemp);

				}

			}

			result = result + etemp2->fn->x1;
			nc = nc + 1;
		}

		spn = splay_tree_successor(usepoe, spn->key);
	}

	if ((result == 0) || (nc == 0)) {
		return (0);
	}

	dresult = (double)result;
	dresult = (dresult / nc /* static_layouter2draw_pos_centerm_upper_connectivity (node) */ );
	dresult = round(dresult);

	return ((int)dresult);
}

/* follow edge outgoing edges until a real node */
static struct uedge *static_layouter2draw_pos_priodown_feo(struct uedge *ue)
{
	struct uedge *ue2 = (struct uedge *)0;
	struct unode *tn1 = (struct unode *)0;

	if (option_placedebug || 0) {
		printf("%s(): scanning \"%s\"->\"%s\" rev=%d horedge=%d\n", __FUNCTION__, ue->fn->name, ue->tn->name,
		       ue->bitflags.reversed, ue->bitflags.horedge);
		tn1 = ue->tn;
		printf("%s(): follow edge is dout=%p din=%p\n", __FUNCTION__, (void *)tn1->dout, (void *)tn1->din);
	}

	if (option_feprio == 0) {
		return (ue);
	}

	/* edge to check */
	ue2 = ue;

	/* do not do horizontal edges, they are on same level */
	if (ue2->bitflags.horedge) {
		return (ue2);
	}

	/* keep scanning */
	while (ue2) {

		/* accept edgelabel as real node. */
		if (ue2->tn->bitflags.dummynode == 0) {
			break;
		}

		/* take outgoing edge from dummy node */
		ue2 = ue2->tn->dout;

		if (ue2 == (struct uedge *)0) {
			/* shouldnothappen */
			break;
		}

	}

	if (ue2 == (struct uedge *)0) {
		printf("%s(): did not find edge ue2\n", __FUNCTION__);
		/* safety return, the original edge */
		return ((struct uedge *)ue);
	}

	return ((struct uedge *)ue2);
}

/* */
static int static_layouter2draw_pos_centerm_lower_barycenter(struct unode *node)
{
	int result = 0;
	splay_tree usepoe = (splay_tree) 0;
	splay_tree_node spn = (splay_tree_node) 0;
	struct uedge *ue = (struct uedge *)0;
	struct uedge *etemp = (struct uedge *)0;
	struct uedge *etemp2 = (struct uedge *)0;
	double dresult = 0.0;
	int nc = 0;

	/* edges connected to this node */
	usepoe = node->sp_poe;

	spn = splay_tree_min(usepoe);

	result = 0;

	/* scan the edges connected to this node */
	while (spn) {

		/* this edge is connected to node ufn */
		ue = (struct uedge *)spn->value;

		/* outgoing edges */
		if (ue->fn == node) {
			/* skip hor. edges */
			if (ue->bitflags.horedge) {
				spn = splay_tree_successor(usepoe, spn->key);
				continue;
			}

			etemp = ue->tn->dout;
			etemp2 = etemp;

			if (etemp) {

				if (option_placedebug || 0) {
					printf("%s(): outgoing edge at node \"%s\" is \"%s\"->\"%s\"->\"%s\"\n", __FUNCTION__,
					       ue->fn->name, ue->fn->name, etemp->fn->name, etemp->tn->name);
				}

				/* search edge if target is not a real node */
				if ((etemp->tn->bitflags.dummynode == 1) || (etemp->tn->bitflags.edgelabel == 1)
				    || (ue->fn->bitflags.dummynode)) {

					/* scan connected edges, always return a valid etemp2 */
					etemp2 = static_layouter2draw_pos_priodown_feo(etemp);
				}
			}

			result = result + etemp2->tn->x1;
			nc = nc + 1;
		}

		spn = splay_tree_successor(usepoe, spn->key);
	}

	if ((result == 0) || (nc == 0)) {
		return (0);
	}

	dresult = (double)result;
	dresult = (dresult / nc /* static_layouter2draw_pos_centerm_lower_connectivity (node) */ );
	dresult = round(dresult);

	return ((int)dresult);
}

/* srt */
static void static_layouter2draw_pos_centerm_sort(int n)
{
	int i = 0;
	int j = 0;
	struct priority_data h;

	for (j = n - 1; j > 0; j--) {
		for (i = 0; i < j; i++) {
			if (nl[i].node->x1 > nl[i + 1].node->x1) {
				h = nl[i];
				nl[i] = nl[i + 1];
				nl[i + 1] = h;
			}
		}
	}

	return;
}

/* set node data */
static void static_layouter2draw_pos_centerm_make_node_list_down(int level)
{
	struct dli *lp = NULL;
	struct ddn *dnptr = NULL;
	int i = 0;

	/* get current layer */
	lp = dlip[level];

	/* scan nodes in layer */
	dnptr = lp->nl;

	i = 0;

	/* */
	while (dnptr) {
		nl[i].node = dnptr->dn->un;
		nl[i].done = 0;

		if (nl[i].node == NULL) {
			printf("%s(): shouldnothappen\n", __FUNCTION__);
			fflush(stdout);
			return;
		}

		if (nl[i].node->bitflags.dummynode) {
			nl[i].priority = (1000 * (dlip[level - 2]->nnodes + 1));
		} else {
			nl[i].priority = static_layouter2draw_pos_centerm_upper_connectivity(nl[i].node);
		}

		i++;

		dnptr = dnptr->next;
	}

	static_layouter2draw_pos_centerm_sort(dlip[level]->nnodes);

	return;
}

/* set node data */
static void static_layouter2draw_pos_centerm_make_node_list_up(int level)
{
	struct dli *lp = NULL;
	struct ddn *dnptr = NULL;
	int i = 0;

	/* get current layer */
	lp = dlip[level];

	/* scan nodes in layer */
	dnptr = lp->nl;

	i = 0;

	/* */
	while (dnptr) {
		nl[i].node = dnptr->dn->un;
		nl[i].done = 0;

		if (nl[i].node->bitflags.dummynode) {
			/* dummynodes get high priority during drawing layout */
			if (level < (dli_nlevels - 2)) {
				nl[i].priority = (1000 * (dlip[level + 2]->nnodes + 1));
			} else {
				nl[i].priority = 1000;
			}
		} else {
			nl[i].priority = static_layouter2draw_pos_centerm_lower_connectivity(nl[i].node);
		}

		i++;

		dnptr = dnptr->next;
	}

	static_layouter2draw_pos_centerm_sort(dlip[level]->nnodes);

	return;
}

/* get next priority */
static int static_layouter2draw_pos_centerm_find_next(int level, int n)
{
	int index = 0;
	int i = 0;
	int highest_priority = 0;

	for (i = 0; i < n; i++) {
		if ((nl[i].priority >= highest_priority) && (nl[i].done == 0)) {
			index = i;
			highest_priority = nl[i].priority;
		}
	}

	if (option_placedebug || 0) {
		printf("%s(): level=%d nnodes=%d found node-at-pos=%d priority=%d\n", __FUNCTION__, level, n, index,
		       highest_priority);
	}

	return (index);
}

/* */
static int static_layouter2draw_pos_centerm_minimum(int x, int y)
{
	if (x < y) {
		return (x);
	} else {
		return (y);
	}
}

/* downwards */
static void static_layouter2draw_pos_centerm__down(int l)
{
	int i = 0;
	int index = 0;
	int j = 0;
	int optimal_position = 0;
	int distance = 0;
	int possible_distance = 0;
	int d = 0;
	int k = 0;
	int md = 0;
	double dxspacing = 0.0;
	struct unode *ufn = (struct unode *)0;

	/* spacing x dir */
	dxspacing = (xspreading * option_xyspread);

	/* x spacing between the nodes */
	md = (int)dxspacing;

	for (i = 0; i < dlip[l]->nnodes; i++) {
		if (option_placedebug || 0) {
			printf("%s(): --- doing node %d of %d nodes in level %d\n", __FUNCTION__, i, dlip[l]->nnodes, l);
		}

		/* find node with highest priority in level which is not yet handled */
		index = static_layouter2draw_pos_centerm_find_next(l, dlip[l]->nnodes);

		optimal_position = static_layouter2draw_pos_centerm_upper_barycenter(nl[index].node);

		/* node to consider */
		ufn = nl[index].node;

		if (option_placedebug || 0) {
			printf("%s(): optimal position=%d for node at pos %d \"%s\" at x1=%d\n", __FUNCTION__, optimal_position,
			       index, nl[index].node->name, nl[index].node->x1);
		}

		if (optimal_position == 0) {
			optimal_position = nl[index].node->x0;
		}

		if (optimal_position < nl[index].node->x1) {
			distance = nl[index].node->x1 - optimal_position;

			if (option_placedebug || 0) {
				printf("%s(): about to move left %d px node \"%s\"\n", __FUNCTION__, distance,
				       nl[index].node->name);
			}

			possible_distance = 0;
			j = index;

			do {
				if (j > 0) {
					possible_distance =
					    (possible_distance + (nl[j].node->x0) -
					     (nl[j - 1].node->x0 + nl[j - 1].node->bbx + md));
				} else {
					/* j==0 */
					possible_distance = (possible_distance + (nl[j].node->x0 + nl[j].node->bbx + md));
				}
				j--;
			}
			while ((j >= 0) && (nl[j].done == 0));

			if (option_placedebug || 0) {
				printf("%s(): left moving for node \"%s\" possible_distance=%d and distance=%d\n", __FUNCTION__,
				       ufn->name, possible_distance, distance);
			}

			if (possible_distance < distance) {
				distance = possible_distance;
			}

			j = index;

			while (distance > 0) {

				if (j == 0) {
					d = distance;
				} else {
					d = static_layouter2draw_pos_centerm_minimum((nl[j].node->x0) -
										     (nl[j - 1].node->x0 + nl[j - 1].node->bbx +
										      md), distance);
				}

				for (k = j; k <= index; k++) {

					static_layouter2draw_pos_centerm_mvnode(nl[k].node, -(d));

					if (option_placedebug || 0) {
						printf("%s(): left going for node \"%s\" moving node \"%s\" %d px\n", __FUNCTION__,
						       ufn->name, nl[k].node->name, -d);
					}

				}

				j--;
				distance = (distance - d);
			}
		} else {
			/* here if (optimal_position >= (nl[index].node->x0) */

			distance = (optimal_position - nl[index].node->x1);

			if (option_placedebug || 0) {
				printf("%s(): about to move right distance=%d px node \"%s\"\n", __FUNCTION__, distance,
				       nl[index].node->name);
			}

			/* how much move before a "done" node is hit */
			possible_distance = 0;
			j = index;

			do {

				if (option_placedebug || 0) {
					printf("%s(): check for node \"%s\" node \"%s\" done=%d\n", __FUNCTION__, ufn->name,
					       nl[j].node->name, nl[j].done);
				}

				if (j < dlip[l]->nnodes - 1) {
					possible_distance =
					    (possible_distance + (nl[j + 1].node->x0) - (nl[j].node->x0 + nl[j].node->bbx + md));

					if (option_placedebug || 0) {
						printf("%s(): check for node \"%s\" node \"%s\" done=%d possible_distance=%d\n",
						       __FUNCTION__, ufn->name, nl[j + 1].node->name, nl[j + 1].done,
						       possible_distance);
					}

				} else {
					/* last node */
					possible_distance = (possible_distance + distance);
				}

				j++;
			}
			while ((j < dlip[l]->nnodes) && (nl[j].done == 0));

			if (option_placedebug || 0) {
				printf("%s(): right moving for node \"%s\" possible_distance=%d and distance=%d\n", __FUNCTION__,
				       ufn->name, possible_distance, distance);
			}

			/* set how far we can move now, considering the blocking by a "done" node */
			if (possible_distance < distance) {
				distance = possible_distance;
			}

			j = index;

			if (option_placedebug || 0) {
				printf("%s(): for node \"%s\" distance=%d px to move now\n", __FUNCTION__, ufn->name, distance);
			}

			while (distance > 0) {

				if (j == (dlip[l]->nnodes - 1)) {
					/* last node at this level */
					d = distance;
				} else {
					d = static_layouter2draw_pos_centerm_minimum((nl[j + 1].node->x0) -
										     (nl[j].node->x0 + nl[j].node->bbx + md),
										     distance);
				}

				for (k = index; k <= j; k++) {

					if (option_placedebug || 0) {
						printf("%s(): right going for node \"%s\" moving node \"%s\" %d px\n", __FUNCTION__,
						       ufn->name, nl[k].node->name, d);
					}

					static_layouter2draw_pos_centerm_mvnode(nl[k].node, d);
				}

				j++;
				distance = (distance - d);
			}

		}

		nl[index].done = 1;
	}

	return;
}

/* upwards */
static void static_layouter2draw_pos_centerm__up(int l)
{
	int i = 0;
	int index = 0;
	int j = 0;
	int optimal_position = 0;
	int distance = 0;
	int possible_distance = 0;
	int d = 0;
	int k = 0;
	int md = 0;
	double dxspacing = 0.0;

	/* spacing x dir */
	dxspacing = xspreading * option_xyspread;

	/* x spacing between the nodes */
	md = (int)dxspacing;

	for (i = 0; i < dlip[l]->nnodes; i++) {

		if (option_placedebug || 0) {
			printf("%s(): --- check node %d of %d nodes in level %d\n", __FUNCTION__, i, dlip[l]->nnodes, l);
		}

		/* find node with highest priority in level which is not yet handled */
		index = static_layouter2draw_pos_centerm_find_next(l, dlip[l]->nnodes);

		optimal_position = static_layouter2draw_pos_centerm_lower_barycenter(nl[index].node);

		if (option_placedebug || 0) {
			printf("%s(): optimal_position=%d x1=%d for node \"%s\" at index-pos=%d\n", __FUNCTION__, optimal_position,
			       nl[index].node->x1, nl[index].node->name, index);
		}

		if (optimal_position == 0) {
			optimal_position = nl[index].node->x0;
		}

		if (optimal_position < nl[index].node->x1) {
			distance = nl[index].node->x1 - optimal_position;

			possible_distance = 0;

			j = index;

			do {
				if (j > 0) {
					possible_distance =
					    (possible_distance + (nl[j].node->x0) -
					     (nl[j - 1].node->x0 + nl[j - 1].node->bbx + md));
				} else {
					/* j==0 */
					possible_distance = (possible_distance + (nl[0].node->x0 + nl[0].node->bbx + md));
				}
				j--;
			}
			while ((j >= 0) && (nl[j].done == 0));

			if (possible_distance < distance) {
				distance = possible_distance;
			}

			j = index;

			while (distance > 0) {

				if (j == 0) {
					d = distance;
				} else {
					d = static_layouter2draw_pos_centerm_minimum((nl[j].node->x0) -
										     (nl[j - 1].node->x0 + nl[j - 1].node->bbx +
										      md), distance);
				}

				for (k = j; k <= index; k++) {

					static_layouter2draw_pos_centerm_mvnode(nl[k].node, -(d));

				}

				j--;

				distance = (distance - d);
			}
		} else {
			/* here if (optimal_position >= nl[index].node->x1P) */
			distance = optimal_position - nl[index].node->x1;

			possible_distance = 0;
			j = index;

			do {

				if (j < dlip[l]->nnodes - 1) {
					possible_distance =
					    (possible_distance + (nl[j + 1].node->x0) - (nl[j].node->x0 + nl[j].node->bbx + md));
				} else {
					possible_distance = (possible_distance + distance);
				}

				j++;
			}
			while ((j < dlip[l]->nnodes) && (nl[j].done == 0));

			if (possible_distance < distance) {
				distance = possible_distance;
			}

			j = index;

			while (distance > 0) {

				if (j == dlip[l]->nnodes - 1) {
					d = distance;
				} else {
					d = static_layouter2draw_pos_centerm_minimum((nl[j + 1].node->x0) -
										     (nl[j].node->x0 + nl[j].node->bbx + md),
										     distance);
				}

				for (k = index; k <= j; k++) {

					static_layouter2draw_pos_centerm_mvnode(nl[k].node, d);

				}

				j++;

				distance = (distance - d);
			}
		}
		nl[index].done = 1;
	}

	return;
}

/* move drawing */
static int static_layouter2draw_pos_centerm_mvdraw(void)
{
	int tmp0 = 0;
	int i = 0;
	struct dli *lp = NULL;
	struct ddn *dnptr = NULL;
	struct ddn *dnptrnext = NULL;
	int nfail = 0;

	/* assume max right pos. */
	tmp0 = 999999;

	/* check how far image left from (0,0) origin now (but it can also be at right) */
	for (i = 0; i < dli_nlevels; i++) {
		/* get current layer */
		lp = dlip[i];

		/* scan nodes in layer */
		dnptr = lp->nl;

		if (dnptr) {

			/* left-most node should have lowest x pos */
			if (dnptr->dn->un->x0 < tmp0) {
				tmp0 = dnptr->dn->un->x0;
			}

		}

	}

	/* if(tmp0>0) this can happen */

	nfail = 0;

	/* move drawing horizontal and determine x size */
	maxx = 0;

	/* if dfs starts at 1 */
	for (i = dfsstartlevel; i < dli_nlevels; i++) {
		/* get current layer */
		lp = dlip[i];

		/* scan nodes in layer */
		dnptr = lp->nl;

		/* position the drawing to the left */
		while (dnptr) {

			/* move 1 node in level */
			static_layouter2draw_pos_centerm_mvnode(dnptr->dn->un, -tmp0);

			/* determine max x pos */
			if ((dnptr->dn->un->x0 + dnptr->dn->un->bbx) > maxx) {
				maxx = (dnptr->dn->un->x0 + dnptr->dn->un->bbx);
			}

			/* check integrity */
			dnptrnext = dnptr->next;

			if (dnptrnext) {

				/* check the actual x position */
				if (((dnptr->dn->un->x0 + dnptr->dn->un->bbx) > (dnptrnext->dn->un->x0 - tmp0))) {
					nfail = nfail + 1;
					fprintf(stderr,
						"%s() x0-pos failure at level %d node number=[n%d] pos=%d x0=%d next-x0=%d \"%s\" \"%s\"\n",
						__FUNCTION__, i, dnptr->dn->un->number, dnptr->dn->un->pos, dnptr->dn->un->x0,
						(dnptrnext->dn->un->x0 - tmp0), dnptr->dn->un->name, dnptr->dn->un->label);
				}

				/* check the barycenter position */
				if (dnptr->dn->un->pos > dnptrnext->dn->un->pos) {
					printf
					    ("%s() pos failure at level %d node number=[n%d] pos=%d x0=%d next-x0=%d next-pos=%d \"%s\" \"%s\"\n",
					     __FUNCTION__, i, dnptr->dn->un->number, dnptr->dn->un->pos, dnptr->dn->un->x0,
					     (dnptrnext->dn->un->x0 - tmp0), dnptrnext->dn->un->pos, dnptr->dn->un->name,
					     dnptr->dn->un->label);
				}

			}

			dnptr = dnptr->next;
		}
	}

	/* include size of level 0 if needed and not yet counted */
	if (dfsstartlevel) {

		/* get current layer */
		lp = dlip[0];

		/* scan nodes in layer */
		dnptr = lp->nl;

		/* move all nodes in level same amount */
		while (dnptr) {

			/* determine max x pos */
			if (dnptr->dn->un->x0 + dnptr->dn->un->bbx > maxx) {
				maxx = dnptr->dn->un->x0 + dnptr->dn->un->bbx;
			}

			dnptr = dnptr->next;
		}
	}

	/* return how many defects found in drawing data */
	return (nfail);
}

/* debug print nodes in levels */
static void static_layouter2draw_pos_centerm_prlevels(void)
{
	int i = 0;
	struct dli *lp = NULL;
	struct ddn *dnptr = NULL;
	struct unode *ufn = (struct unode *)0;

	if (option_placedebug || 0) {
		printf("%s(): drawing size (%d,%d)\n", __FUNCTION__, maxx, maxy);

		/* print the state of the nodes in the levels at start */
		for (i = dfsstartlevel; i < dli_nlevels; i = i + 2) {

			/* get current layer */
			lp = dlip[i];

			/* scan nodes in layer */
			dnptr = lp->nl;

			while (dnptr) {
				ufn = dnptr->dn->un;
				printf("%s(): node \"%s\" \"%s\" indeg=%d outdeg=%d is at pos %d x0=%d x1=%d bbx=%d level=%d\n",
				       __FUNCTION__, ufn->name, ufn->label, ufn->indegree, ufn->outdegree, ufn->pos, ufn->x0,
				       ufn->x1, ufn->bbx, i);
				dnptr = dnptr->next;
			}

		}

	}

	return;
}

/* init */
static void static_layouter2draw_pos_centerm_init(void)
{

	/* using left-most mode as initial
	 * then the top level summary nodes
	 * are at place and not moved
	 */
	layouter2draw_x0_left();

	/* set y level positions */
	layouter2draw_y0();

	return;
}

/* check if it can run in this mode */
static void static_layouter2draw_pos_centerm_chk(void)
{

	/* relayout if there is a extra dummynode level */
	if (levelextra) {

		/* only 1 intermediate level with dummy nodes */
		levelextra = 0;
		/* calculate the new graph */
		calculate();
	}

	return;
}

/* prio drawing and median avg */
static void static_layouter2draw_pos_centerm_(void)
{
	int i = 0;
	int nf = 0;
	int nr = 0;
	struct dli *lp = NULL;
	struct ddn *dnptr = NULL;
	struct unode *ufn = (struct unode *)0;
	int lmaxw = 0;
	int lmaxwbbx = 0;
	int lmaxx = 0;

	/* check if it can run in this mode */
	static_layouter2draw_pos_centerm_chk();

	/* set a initial layout */
	static_layouter2draw_pos_centerm_init();

	/* debug print nodes in levels */
	static_layouter2draw_pos_centerm_prlevels();

	/* not much todo if only 1 level */
	if (dli_nlevels == 1) {
		return;
	}

	/* with value >1 random placement errors. */
	for (nr = 0; nr < 1; nr++) {

		/* scan from top of drawing to bottom */
		for (i = dfsstartlevel; i < (dli_nlevels - 0); i = i + 2) {
			nl = (struct priority_data *)mymalloc((dlip[i]->nnodes * sizeof(struct priority_data)), __FUNCTION__,
							      __LINE__);
			static_layouter2draw_pos_centerm_make_node_list_down(i);
			static_layouter2draw_pos_centerm__down(i);
			myfree((void *)nl, __FUNCTION__, __LINE__);
			nl = (struct priority_data *)0;
		}

		/* scan from bottom of drawing to top, higgest level is (dli_nlevels-1) */
		for (i = (dli_nlevels - 1); i >= dfsstartlevel; i = i - 2) {
			nl = (struct priority_data *)mymalloc((dlip[i]->nnodes * sizeof(struct priority_data)), __FUNCTION__,
							      __LINE__);
			static_layouter2draw_pos_centerm_make_node_list_up(i);
			static_layouter2draw_pos_centerm__up(i);
			myfree((void *)nl, __FUNCTION__, __LINE__);
			nl = (struct priority_data *)0;
		}

	}

	/* last one was up(), optional extra down() in different ways */

	/* range 0..3 */
	switch (option_pud) {
	case 0:
		{
			/* do nothing */
		}
		break;
	case 1:
		{
			/* possibility 1: whole drawing */

			/* scan from top of drawing to bottom */
			for (i = dfsstartlevel; i < (dli_nlevels - 0); i = i + 2) {
				nl = (struct priority_data *)mymalloc((dlip[i]->nnodes * sizeof(struct priority_data)),
								      __FUNCTION__, __LINE__);
				static_layouter2draw_pos_centerm_make_node_list_down(i);
				static_layouter2draw_pos_centerm__down(i);
				myfree((void *)nl, __FUNCTION__, __LINE__);
				nl = (struct priority_data *)0;
			}
		}
		break;
	case 2:
		{
			/* extra option: from widest x-positions-level to bottom (edge) */
			/* widest here as in largest x-size, not number of nodes */

			/* level with largest x pos */
			lmaxw = 0;
			lmaxwbbx = 0;

			/* print the state of the nodes in the levels at start */
			for (i = dfsstartlevel; i < dli_nlevels; i = i + 2) {

				/* get current layer */
				lp = dlip[i];

				/* scan nodes in layer */
				dnptr = lp->nl;

				lmaxx = 0;

				while (dnptr) {
					ufn = dnptr->dn->un;
					if (ufn->x0 + ufn->bbx > lmaxx) {
						lmaxx = ufn->x0 + ufn->bbx;
					}
					dnptr = dnptr->next;
				}

				/* update level with biggest x pos. */
				if (lmaxx > lmaxwbbx) {
					lmaxwbbx = lmaxx;
					lmaxw = i;
				}

			}

			printf("level=%d pud=%d\n", lmaxw, option_pud);

			for (i = lmaxw; i < (dli_nlevels - 0); i = i + 2) {
				nl = (struct priority_data *)mymalloc((dlip[i]->nnodes * sizeof(struct priority_data)),
								      __FUNCTION__, __LINE__);
				static_layouter2draw_pos_centerm_make_node_list_down(i);
				static_layouter2draw_pos_centerm__down(i);
				myfree((void *)nl, __FUNCTION__, __LINE__);
				nl = (struct priority_data *)0;
			}

		}
	case 3:
/* XXX widest level as in with most nodes (edge) */
		/* similar extra option from smallest tevel to bottom */
		{
			/* level with smallest x pos */
			lmaxw = 9999;
			lmaxwbbx = 9999;

			/* print the state of the nodes in the levels at start */
			for (i = dfsstartlevel; i < dli_nlevels; i = i + 2) {

				/* get current layer */
				lp = dlip[i];

				/* scan nodes in layer */
				dnptr = lp->nl;

				lmaxx = 0;

				do {
					ufn = dnptr->dn->un;
					if (ufn->x0 + ufn->bbx < lmaxx) {
						lmaxx = ufn->x0 + ufn->bbx;
					}
					dnptr = dnptr->next;
				}
				while (dnptr);

				/* update level with biggest x pos. */
				if (lmaxx < lmaxwbbx) {
					lmaxwbbx = lmaxx;
					lmaxw = i;
				}

			}
			printf("level=%d pud=%d\n", lmaxw, option_pud);

			for (i = lmaxw; i < (dli_nlevels - 0); i = i + 2) {
				nl = (struct priority_data *)mymalloc((dlip[i]->nnodes * sizeof(struct priority_data)),
								      __FUNCTION__, __LINE__);
				static_layouter2draw_pos_centerm_make_node_list_down(i);
				static_layouter2draw_pos_centerm__down(i);
				myfree((void *)nl, __FUNCTION__, __LINE__);
				nl = (struct priority_data *)0;
			}

		}
		break;
	default:
		/* shouldnothappen */
		break;
	}

	/* debug print nodes in levels */
	static_layouter2draw_pos_centerm_prlevels();

	/* move drawing */
	nf = static_layouter2draw_pos_centerm_mvdraw();

	/* only if there are fails in drawing data */
	if (nf) {
		/* try fix overlap */
		fprintf(stderr, "%s(): try to fix draw data... fixme\n", __FUNCTION__);
		static_layouter2draw_pos_centerm_fixo();
	}

	/* fix interleaved dummy */
	static_layouter2draw_pos_centerm_fixdummy();

	/* now the minimal "priority method" as described in the book of kozo sugiyama
	 * has been done, another stege is needed to get similar results as dot program.
	 */

	return;
}

/*t*/

/* prio drawing and median avg */
static void static_layouter2draw_pos_centern_(void)
{
/* to add in here */
	return;
}

/* */
static void static_layouter2draw_pos(void)
{
	splay_tree_node spn = (splay_tree_node) 0;
	char *s = NULL;
	char *sh = NULL;
	struct unode *un = (struct unode *)0;
	struct uedge *ue = (struct uedge *)0;

	/* move x pos of nodes such that is a more spreaded drawing */
	update_statusline("Moving drawing around... Wait...");

	if (option_testcode || 0) {
		printf("/* graph layout at start of %s() */\n", __FUNCTION__);
		printf("digraph \"at-%s()\" {\n", __FUNCTION__);
		if (splay_tree_has_data(sp_parsedwnl)) {
			spn = splay_tree_min(sp_parsedwnl);
			while (spn) {
				un = (struct unode *)spn->value;
				if (un->bitflags.dummynode) {
					s = "red";
					sh = "box";
				} else {
					s = "black";
					sh = "ellipse";
				}

				printf(" \"n%d\"[color=\"%s\",shape=\"%s\",label=\"%s\\llevel=%d\\lpos=%d\\llabel=%s\"];\n",
				       un->number, s, sh, un->name, un->level, un->pos, un->label);
				spn = splay_tree_successor(sp_parsedwnl, spn->key);
			}
		}

		if (splay_tree_has_data(sp_parsedwel)) {
			spn = splay_tree_min(sp_parsedwel);
			while (spn) {
				ue = (struct uedge *)spn->value;
				if (ue->bitflags.reversed) {
					s = "red";
				} else {
					s = "black";
				}

				printf(" \"n%d\"->\"n%d\"[label=\"e%d\",color=\"%s\"];\n", ue->fn->number, ue->tn->number,
				       ue->number, s);
				spn = splay_tree_successor(sp_parsedwel, spn->key);
			}
		}

		printf("}\n/* dummynodes are red, reversed edges are red */\n");
	}

	/* calculate node positions in the levels.
	 * todo: at this stage the order of the nodes in the levels
	 * is set with node->pos by barycenter algorithm.
	 * now move the nodes around in x direction to
	 * create a "readable" drawing whatever that means.
	 * That can be done in many ways and steps and
	 * there is no official or best algorithm for it.
	 */
	switch (xplace_mode) {
	case XPLACE_CENTERM:
		/* easiest rubberbanding */
		static_layouter2draw_pos_centerm_();
		break;
	case XPLACE_CENTERN:
		/* other rubberbanding */
		static_layouter2draw_pos_centern_();
		break;
		/* follow the nodes from the outgoing edges */
	case XPLACE_FOLLOWO:
		layouter2draw_x0_followingo();
		break;
		/* follow the nodes from the incoming edges */
	case XPLACE_FOLLOWI:
		layouter2draw_x0_followingi();
		break;
		/* follow the nodes from the incoming edges */
	case XPLACE_FOLLOWL:
		layouter2draw_x0_followingl();
		break;
		/* follow the nodes from the incoming edges */
	case XPLACE_FOLLOWR:
		layouter2draw_x0_followingr();
		break;
		/* place left most */
	case XPLACE_LEFT:
		layouter2draw_x0_left();
		break;
		/* place every level centered in the drawing */
	case XPLACE_CENTERED:
		layouter2draw_x0_centered();
		break;
	default:
		layouter2draw_x0_followingo();
		break;
	}

	/* calculate y0 of layer */
	switch (xplace_mode) {
	case XPLACE_CENTERM:
		break;
		/* fallthru */
	case XPLACE_FOLLOWO:
	case XPLACE_FOLLOWI:
	case XPLACE_FOLLOWL:
	case XPLACE_FOLLOWR:
	case XPLACE_LEFT:
	case XPLACE_CENTERED:
	default:
		layouter2draw_y0();
		break;
	}

	/* calculate subgraph area */
	calc_subgraph_area();
	/* option here to put expanded subgraphs at top level next to each other instead of overlap */
	/* make sure drawing is at least 1x1 1 pixel */
	if (maxx == 0) {
		maxx = 1;
	}

	if (maxy == 0) {
		maxy = 1;
	}

	/* adjust the border */
	maxx = maxx + xoffset;
	maxy = maxy + yoffset;

	update_statusline("Drawing Ready");

	return;
}

/* calculate x0 of layer */
static void layouter2draw_x0_centered(void)
{
	int i = 0;
	struct dli *lp = NULL;
	int maxw = 0;
	int w = 0;
	struct ddn *dnptr = NULL;
	double dxspacing = 1.0;
	int xspacing = 0;
	int delta = 0;
	int sx = 0;
	/* drawing x size 0 to re-calculate */
	maxx = 1;
	/* max seen x size of layer */
	maxw = 0;

	/* spacing x dir */
	dxspacing = xspreading * option_xyspread;

	/* x spacing between the nodes */
	xspacing = (int)dxspacing;

	/* scan layers */
	for (i = 0; i < dli_nlevels; i++) {
		/* get current layer */
		lp = dlip[i];
		/* width of layer */
		lp->wn = 0;
		/* x size of layer */
		w = 0;
		/* add drawing x offset */
		w = w + xoffset;
		/* scan nodes in layer */
		dnptr = lp->nl;
		while (dnptr) {
			/* add x size of node */
			w = w + dnptr->dn->un->bbx;
			/* add x spacing between nodes */
			w = w + xspacing;
			dnptr = dnptr->next;
		}

		/* save total width of this layer */
		lp->wn = w;
		/* check for max */
		if (w > maxw) {
			maxw = w;
		}

		/* */
		if (option_ldebug > 1) {
			printf("%s(): layer[%d] has x size %d (max=%d)\n", __FUNCTION__, i, w, maxw);
			fflush(stdout);
		}
	}

	/* set max x size of drawing scaled 1:1 */
	if (maxw > maxx) {
		maxx = maxw;
	}

	/* scan layers and set start of layer */
	for (i = 0; i < dli_nlevels; i++) {
		lp = dlip[i];
		/* reset start of layer */
		lp->x0 = 0;
		/* add x offset of drawing */
		lp->x0 = lp->x0 + xoffset;
		/* */
		delta = maxw - lp->wn;
		/* */
		delta = delta / 2;
		/* set start of layer */
		lp->x0 = lp->x0 + delta;
		if (option_ldebug > 1) {
			printf("%s(): layer[%d] starts at x %d (maxx=%d)\n", __FUNCTION__, i, lp->x0, maxx);
			fflush(stdout);
		}

		/* update nodes starting x */
		sx = lp->x0;
		/* scan nodes in layer */
		dnptr = lp->nl;
		while (dnptr) {
			/* set x0 and x1 of node */
			dnptr->dn->un->x0 = sx;
			dnptr->dn->un->x1 = (dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2));
			/* add x size of node */
			sx = sx + dnptr->dn->un->bbx;
			/* add x spacing */
			sx = sx + xspacing;
			dnptr = dnptr->next;
		}
	}

	return;
}

/* calculate x0 of layer */
static void layouter2draw_x0_left(void)
{
	int i = 0;
	struct dli *lp = NULL;
	int maxw = 0;
	int w = 0;
	struct ddn *dnptr = NULL;
	double dxspacing = 1.0;
	int xspacing = 0;
	int delta = 0;
	int sx = 0;

	/* drawing x size 0 to re-calculate */
	maxx = 1;

	/* max seen x size of layer */
	maxw = 0;

	/* spacing x dir */
	dxspacing = xspreading * option_xyspread;

	/* x spacing between the nodes */
	xspacing = (int)dxspacing;

	/* scan layers */
	for (i = 0; i < dli_nlevels; i++) {
		/* get current layer */
		lp = dlip[i];
		/* width of layer */
		lp->wn = 0;
		/* x size of layer */
		w = 0;
		/* add drawing x offset */
		w = w + xoffset;
		/* scan nodes in layer */
		dnptr = lp->nl;
		while (dnptr) {
			/* add x size of node */
			w = w + dnptr->dn->un->bbx;
			/* add x spacing between nodes */
			w = w + xspacing;
			dnptr = dnptr->next;
		}

		/* save total width of this layer */
		lp->wn = w;
		/* check for max */
		if (w > maxw) {
			maxw = w;
		}

		/* */
		if (option_ldebug > 1) {
			printf("%s(): layer[%d] has x size %d (max=%d)\n", __FUNCTION__, i, w, maxw);
			fflush(stdout);
		}
	}

	/* set max x size of drawing scaled 1:1 */
	if (maxw > maxx) {
		maxx = maxw;
	}

	/* scan layers and set start of layer */
	for (i = 0; i < dli_nlevels; i++) {
		lp = dlip[i];
		/* reset start of layer */
		lp->x0 = 0;
		/* add x offset of drawing */
		lp->x0 = lp->x0 + xoffset;
		/* */
		delta = maxw - lp->wn;
		/* */
		delta = delta / 2;
		/* left align instead of center */
		delta = 0;
		/* set start of layer */
		lp->x0 = lp->x0 + delta;
		if (option_ldebug > 1) {
			printf("%s(): layer[%d] starts at x %d (maxx=%d)\n", __FUNCTION__, i, lp->x0, maxx);
			fflush(stdout);
		}

		/* update nodes starting x */
		sx = lp->x0;
		/* scan nodes in layer */
		dnptr = lp->nl;
		while (dnptr) {
			/* set x0 and x1 of node */
			dnptr->dn->un->x0 = sx;
			dnptr->dn->un->x1 = (dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2));
			/* add x size of node */
			sx = sx + dnptr->dn->un->bbx;
			/* add x spacing */
			sx = sx + xspacing;
			dnptr = dnptr->next;
		}
	}

	return;
}

/* calculate x0 of layer */
static void layouter2draw_x0_followingi(void)
{
	int i = 0;
	struct dli *lp = NULL;
	int maxw = 0;
	int w = 0;
	struct ddn *dnptr = NULL;
	double dxspacing = 1.0;
	int xspacing = 0;
	splay_tree usepoe = (splay_tree) 0;
	splay_tree_node spn = (splay_tree_node) 0;
	struct uedge *ue = (struct uedge *)0;
	int np = 0;
	int xsum = 0;
	int nx1 = 0;
	int nx0 = 0;

	/* drawing x size 0 to re-calculate */
	maxx = 1;

	/* max seen x size of layer */
	maxw = 0;

	/* spacing x dir as double var */
	dxspacing = xspreading * option_xyspread;

	/* x spacing between the nodes */
	xspacing = (int)dxspacing;

	/* scan layers */
	for (i = 0; i < dli_nlevels; i++) {
		/* get current layer */
		lp = dlip[i];
		/* reset start of layer */
		lp->x0 = 0;
		/* x size of layer */
		w = 0;
		/* add drawing x offset */
		w = w + xoffset;
		/* add x offset of drawing */
		lp->x0 = lp->x0 + xoffset;
		/* scan nodes in layer */
		dnptr = lp->nl;
		while (dnptr) {
			/* get part-of-edge list of node */
			usepoe = dnptr->dn->un->sp_poe;
			/* check node edge connections */
			if (splay_tree_has_data(usepoe) == 0) {
				/* node has no edge connections */
				/* set x0 and x1 of node */
				dnptr->dn->un->x0 = w;
				dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
				/* add x size of node */
				w = w + dnptr->dn->un->bbx;
				/* add x spacing between nodes */
				w = w + xspacing;
			} else {
				/* scan edges connected to node */
				np = 0;
				xsum = 0;
				nx1 = 0;
				nx0 = 0;
				spn = splay_tree_min(usepoe);
				while (spn) {
					ue = (struct uedge *)spn->value;
					/* get incoming edges */
					if (ue->tn == dnptr->dn->un) {
						np = (np + 1);
						/* add center of from node */
						xsum = (xsum + ue->fn->x1);
					}

					spn = splay_tree_successor(usepoe, spn->key);
				}

				/* number of found incoming edges */
				if (np) {
					/* avarage of incoming edges from position */
					nx1 = (xsum / np);
					nx0 = (nx1 - dnptr->dn->un->bbx);
					/* check if new x0 is available */
					if (nx0 >= w) {
						/* nx0 is free pos. move w */
						w = nx0;
					}
					/* set x0 and x1 of node */
					dnptr->dn->un->x0 = w;
					dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
					/* add x size of node */
					w = w + dnptr->dn->un->bbx;
					/* add x spacing between nodes */
					w = w + xspacing;
				} else {
					/* no incoming edges */
					/* add to current */
					/* set x0 and x1 of node */
					dnptr->dn->un->x0 = w;
					w = dnptr->dn->un->x0;
					dnptr->dn->un->x1 = (dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2));
					/* add x size of node */
					w = (w + dnptr->dn->un->bbx);
					/* add x spacing between nodes */
					w = (w + xspacing);
				}
			}

			/* next node */
			dnptr = dnptr->next;
		}

		/* save total width x-size of this layer with its offset */
		lp->wn = (w + xspacing);
		/* check for max */
		if (w > maxw) {
			maxw = w;
		}
		/* check if hit new max x-size of drawing */
		if (maxw > maxx) {
			maxx = maxw;
		}
		/* to next layer */
	}

	return;
}

/* calculate x0 of layer */
static void layouter2draw_x0_followingl(void)
{
	int i = 0;
	struct dli *lp = NULL;
	int maxw = 0;
	int w = 0;
	struct ddn *dnptr = NULL;
	double dxspacing = 1.0;
	int xspacing = 0;
	int np = 0;
	int xsum = 0;
	int nx1 = 0;
	int nx0 = 0;
	splay_tree usepoe = (splay_tree) 0;
	splay_tree_node spn = (splay_tree_node) 0;
	struct uedge *ue = (struct uedge *)0;

	/* drawing x size 0 to re-calculate */
	maxx = 1;

	/* max seen x size of layer */
	maxw = 0;

	/* spacing x dir */
	dxspacing = xspreading * option_xyspread;

	/* x spacing between the nodes */
	xspacing = (int)dxspacing;

	/* scan layers */
	for (i = 0; i < dli_nlevels; i++) {
		/* get current layer */
		lp = dlip[i];
		/* reset start of layer */
		lp->x0 = 0;
		/* x size of layer */
		w = 0;
		/* add drawing x offset */
		w = w + xoffset;
		/* add x offset of drawing */
		lp->x0 = lp->x0 + xoffset;
		/* scan nodes in layer */
		dnptr = lp->nl;
		while (dnptr) {
			/* get part-of-edge list of node */
			usepoe = dnptr->dn->un->sp_poe;
			/* check node edge connections */
			if (splay_tree_has_data(usepoe) == 0) {
				/* node has no edge connections */
				/* set x0 and x1 of node */
				dnptr->dn->un->x0 = w;
				dnptr->dn->un->x1 = (dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2));
				/* add x size of node */
				w = (w + dnptr->dn->un->bbx);
				/* add x spacing between nodes */
				w = (w + xspacing);
			} else {
				/* scan edges connected to node */
				np = 0;
				xsum = 0;
				nx1 = 0;
				nx0 = 0;
				spn = splay_tree_min(usepoe);
				while (spn) {
					ue = (struct uedge *)spn->value;
					/* get incoming edges */
					if (ue->tn == dnptr->dn->un) {
						np = (np + 1);
						/* set center of from node */
						if (xsum == 0) {
							xsum = ue->fn->x1;
						} else {
							if (ue->fn->x1 < xsum) {
								xsum = ue->fn->x1;
							}
						}
					}
					spn = splay_tree_successor(usepoe, spn->key);
				}

				/* number of found incoming edges */
				if (np) {
					/* avarage of incoming edges from position */
					nx1 = (xsum / np);
					nx0 = (nx1 - dnptr->dn->un->bbx);
					/* check if new x0 is available */
					if (nx0 > w) {
						w = nx0;
						/* set x0 and x1 of node */
						dnptr->dn->un->x0 = w;
						dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
						/* add x size of node */
						w = w + dnptr->dn->un->bbx;
						/* add x spacing between nodes */
						w = w + xspacing;
					} else {
						/* add to current */
						/* set x0 and x1 of node */
						dnptr->dn->un->x0 = w;
						dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
						/* add x size of node */
						w = w + dnptr->dn->un->bbx;
						/* add x spacing between nodes */
						w = w + xspacing;
					}
				} else {
					/* no incoming edges */
					/* add to current */
					/* set x0 and x1 of node */
					dnptr->dn->un->x0 = w;
					w = dnptr->dn->un->x0;
					dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
					/* add x size of node */
					w = w + dnptr->dn->un->bbx;
					/* add x spacing between nodes */
					w = w + xspacing;
				}
			}

			/* next node */
			dnptr = dnptr->next;
		}

		/* save total width of this layer */
		lp->wn = w;
		/* check for max */
		if (w > maxw) {
			maxw = w;
		}
		/* check if hit new max x-size of drawing */
		if (maxw > maxx) {
			maxx = maxw;
		}

	}

	return;
}

/* calculate x0 of layer */
static void layouter2draw_x0_followingr(void)
{
	int i = 0;
	struct dli *lp = NULL;
	int maxw = 0;
	int w = 0;
	struct ddn *dnptr = NULL;
	double dxspacing = 1.0;
	int xspacing = 0;
	int np = 0;
	int xsum = 0;
	int nx1 = 0;
	int nx0 = 0;
	splay_tree usepoe = (splay_tree) 0;
	splay_tree_node spn = (splay_tree_node) 0;
	struct uedge *ue = (struct uedge *)0;

	/* drawing x size 0 to re-calculate */
	maxx = 1;

	/* max seen x size of layer */
	maxw = 0;

	/* spacing x dir */
	dxspacing = xspreading * option_xyspread;

	/* x spacing between the nodes */
	xspacing = (int)dxspacing;

	/* scan layers */
	for (i = 0; i < dli_nlevels; i++) {
		/* get current layer */
		lp = dlip[i];
		/* reset start of layer */
		lp->x0 = 0;
		/* x size of layer */
		w = 0;
		/* add drawing x offset */
		w = w + xoffset;
		/* add x offset of drawing */
		lp->x0 = lp->x0 + xoffset;
		/* scan nodes in layer */
		dnptr = lp->nl;
		while (dnptr) {
			/* get part-of-edge list of node */
			usepoe = dnptr->dn->un->sp_poe;
			/* check node edge connections */
			if (splay_tree_has_data(usepoe) == 0) {
				/* node has no edge connections */
				/* set x0 and x1 of node */
				dnptr->dn->un->x0 = w;
				dnptr->dn->un->x1 = (dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2));
				/* add x size of node */
				w = (w + dnptr->dn->un->bbx);
				/* add x spacing between nodes */
				w = (w + xspacing);
			} else {
				/* scan edges connected to node */
				np = 0;
				xsum = 0;
				nx1 = 0;
				nx0 = 0;
				spn = splay_tree_min(usepoe);
				while (spn) {
					ue = (struct uedge *)spn->value;
					/* get incoming edges */
					if (ue->tn == dnptr->dn->un) {
						np = (np + 1);
						/* set center of from node */
						if (xsum == 0) {
							xsum = ue->fn->x1;
						} else {
							if (ue->fn->x1 > xsum) {
								xsum = ue->fn->x1;
							}
						}
					}
					spn = splay_tree_successor(usepoe, spn->key);
				}

				/* number of found incoming edges */
				if (np) {
					/* avarage of incoming edges from position */
					nx1 = (xsum / np);
					nx0 = (nx1 - dnptr->dn->un->bbx);
					/* check if new x0 is available */
					if (nx0 > w) {
						w = nx0;
						/* set x0 and x1 of node */
						dnptr->dn->un->x0 = w;
						dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
						/* add x size of node */
						w = w + dnptr->dn->un->bbx;
						/* add x spacing between nodes */
						w = w + xspacing;
					} else {
						/* add to current */
						/* set x0 and x1 of node */
						dnptr->dn->un->x0 = w;
						dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
						/* add x size of node */
						w = w + dnptr->dn->un->bbx;
						/* add x spacing between nodes */
						w = w + xspacing;
					}
				} else {
					/* no incoming edges */
					/* add to current */
					/* set x0 and x1 of node */
					dnptr->dn->un->x0 = w;
					w = dnptr->dn->un->x0;
					dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
					/* add x size of node */
					w = w + dnptr->dn->un->bbx;
					/* add x spacing between nodes */
					w = w + xspacing;
				}
			}

			/* next node */
			dnptr = dnptr->next;
		}

		/* save total width of this layer */
		lp->wn = w;
		/* check for max */
		if (w > maxw) {
			maxw = w;
		}
		/* check if hit new max x-size of drawing */
		if (maxw > maxx) {
			maxx = maxw;
		}

	}

	return;
}

/* calculate x0 of layer */
static void layouter2draw_x0_followingo(void)
{
	int i = 0;
	struct dli *lp = NULL;
	int maxw = 0;
	int w = 0;
	struct ddn *dnptr = NULL;
	double dxspacing = 1.0;
	int xspacing = 0;
	int np = 0;
	int xsum = 0;
	int nx1 = 0;
	int nx0 = 0;
	splay_tree usepoe = (splay_tree) 0;
	splay_tree_node spn = (splay_tree_node) 0;
	struct uedge *ue = (struct uedge *)0;

	/* create initial placement */
	layouter2draw_x0_followingi();

	/* drawing x size 0 to re-calculate */
	maxx = 1;

	/* max seen x size of layer */
	maxw = 0;

	/* spacing x dir */
	dxspacing = xspreading * option_xyspread;

	/* x spacing between the nodes */
	xspacing = (int)dxspacing;

	/* scan layers */
	for (i = 0; i < dli_nlevels; i++) {
		/* get current layer */
		lp = dlip[i];
		/* reset start of layer */
		lp->x0 = 0;
		/* x size of layer */
		w = 0;
		/* add drawing x offset */
		w = w + xoffset;
		/* add x offset of drawing */
		lp->x0 = lp->x0 + xoffset;
		/* scan nodes in layer */
		dnptr = lp->nl;
		while (dnptr) {
			/* get part-of-edge list of node */
			usepoe = dnptr->dn->un->sp_poe;
			/* check node edge connections */
			if (splay_tree_has_data(usepoe) == 0) {
				/* node has no edge connections */
				/* set x0 and x1 of node */
				dnptr->dn->un->x0 = w;
				dnptr->dn->un->x1 = (dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2));
				/* add x size of node */
				w = (w + dnptr->dn->un->bbx);
				/* add x spacing between nodes */
				w = (w + xspacing);
			} else {
				/* scan edges connected to node */
				np = 0;
				xsum = 0;
				nx1 = 0;
				nx0 = 0;
				spn = splay_tree_min(usepoe);
				while (spn) {
					ue = (struct uedge *)spn->value;
					/* get outgoing edges */
					if (ue->fn == dnptr->dn->un) {
						np = (np + 1);
						/* add center of from node */
						xsum = (xsum + ue->fn->x1);
					}
					spn = splay_tree_successor(usepoe, spn->key);
				}

				/* number of found outgoing edges */
				if (np) {
					/* avarage of outgoing edges from position */
					nx1 = (xsum / np);
					nx0 = (nx1 - dnptr->dn->un->bbx);
					/* check if new x0 is available */
					if (nx0 > w) {
						w = nx0;
						/* set x0 and x1 of node */
						dnptr->dn->un->x0 = w;
						dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
						/* add x size of node */
						w = w + dnptr->dn->un->bbx;
						/* add x spacing between nodes */
						w = w + xspacing;
					} else {
						/* add to current */
						/* set x0 and x1 of node */
						dnptr->dn->un->x0 = w;
						dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
						/* add x size of node */
						w = w + dnptr->dn->un->bbx;
						/* add x spacing between nodes */
						w = w + xspacing;
					}
				} else {
					/* no incoming edges */
					/* add to current */
					/* set x0 and x1 of node */
					w = dnptr->dn->un->x0;
					dnptr->dn->un->x1 = dnptr->dn->un->x0 + (dnptr->dn->un->bbx / 2);
					/* add x size of node */
					w = w + dnptr->dn->un->bbx;
					/* add x spacing between nodes */
					w = w + xspacing;
				}
			}

			/* next node */
			dnptr = dnptr->next;
		}

		/* save total width of this layer */
		lp->wn = w;
		/* check for max */
		if (w > maxw) {
			maxw = w;
		}
		/* check if hit new max x-size of drawing */
		if (maxw > maxx) {
			maxx = maxw;
		}

	}

	return;
}

/* calculate y0 of layer */
static void layouter2draw_y0(void)
{
	int i = 0;
	struct dli *lp = NULL;
	struct ddn *dnptr = NULL;
	int maxly = 0;
	int h = 0;
	int delta = 0;
	int yspacing = 0;
	double lphe = 1.0;

	/* default min. y syze of edge crossing height area */
	yspacing = option_xyspread;

	/* drawing y size scaled 1:1 to re-calculate */
	maxy = 1;

	/* scan layers */
	for (i = 0; i < dli_nlevels; i++) {
		/* get level */
		lp = dlip[i];
		/* y size of layer */
		h = 0;
		/* add y offset of drawing */
		h = h + yoffset;
		/* scan nodes in layer */
		dnptr = lp->nl;
		/* scan for node with biggest y size which sets the height of the nodes area */
		while (dnptr) {
			/* check y size of node */
			if (dnptr->dn->un->bby > h) {
				h = dnptr->dn->un->bby;
			}
			dnptr = dnptr->next;
		}

		/* set height of nodes in this layer */
		lp->hn = h;
		/* check max height */
		if (h > maxly) {
			maxly = h;
		}

		if (option_ldebug > 1) {
			printf("%s(): layer[%d] has y size %d (max=%d)\n", __FUNCTION__, i, h, maxly);
		}
	}

	/* helper height */
	h = 0;
	/* scan layers */
	for (i = 0; i < dli_nlevels; i++) {
		/* get level */
		lp = dlip[i];
		/* set start of level */
		lp->y0 = h;
		/* add y offset of drawing */
		lp->y0 = lp->y0 + yoffset;
		/* edge area height depends no number of edges and number of edge crossings */
		/* increase level height depending on edge count and crossing edge count */
		lphe = yspreading * (yspacing + (lp->nedges * 0) + (lp->ncross * 2));
		/* set edge area */
		lp->he = (int)lphe;
		/* limit max edge area y size */
		if (lp->he > 100) {
			lp->he = 100;
		}

		/* set total height of layer is (node+edge) height */
		lp->ht = lp->he + lp->hn;
		/* determine max y size of drawing */
		if ((lp->y0 + lp->ht) > maxy) {
			maxy = (lp->y0 + lp->ht);
		}

		/* next level at edge and node height */
		h = h + lp->he + lp->hn;
		/* */
		if (option_ldebug > 1) {
			printf("%s(): layer[%d] starts at y %d (maxy=%d)\n", __FUNCTION__, i, lp->y0, maxy);
			fflush(stdout);
		}

		/* update it in the nodes */
		dnptr = lp->nl;
		while (dnptr) {
			delta = lp->hn - dnptr->dn->un->bby;
			delta = (delta / 2);
			/* set top/bottom of node */
			dnptr->dn->un->y1 = lp->y0 + delta;
			dnptr->dn->un->y2 = lp->y0 + delta + dnptr->dn->un->bby;
			dnptr = dnptr->next;
		}

	}

	return;
}

/* calculate subgraph area of toplevel subgraphs, not sub-sub levels */
static void calc_subgraph_area(void)
{
	struct usubg *sg = (struct usubg *)0;
	splay_tree_node spn = (splay_tree_node) 0;
	splay_tree_node spn2 = (splay_tree_node) 0;
	struct unode *un = (struct unode *)0;
	if (option_placedebug || 0) {
		printf("%s(): get size of %d subgraphs data=%d\n", __FUNCTION__, n_input_subgraphs,
		       splay_tree_has_data(sp_parsedwsgl));
	}

	/* if no subgraphs skip calc */
	if (n_input_subgraphs == 0) {
		return;
	}

	/* now there should be subgraph data */
	if (splay_tree_has_data(sp_parsedwsgl)) {

		spn = splay_tree_min(sp_parsedwsgl);
		while (spn) {
			sg = (struct usubg *)spn->value;
			sg->bitflags.adone = 0;
			if (option_placedebug) {
				printf("%s(): status folded=%d\n", __FUNCTION__, sg->bitflags.folded);
			}

			if (sg->bitflags.folded == 1) {
				/* in folded state take size of summary node */
				sg->aminx = sg->summaryn->x0;
				sg->aminy = sg->summaryn->y1;
				sg->amaxx = (sg->summaryn->x0 + sg->summaryn->bbx);
				sg->amaxy = (sg->summaryn->y1 + sg->summaryn->bby);
			} else {
				/* in folded state take size of all nodes rooted in this subgraph */
				sg->aminx = maxx;
				sg->aminy = maxy;
				sg->amaxx = 0;
				sg->amaxy = 0;
				if (splay_tree_has_data(sg->sp_nl)) {

					/* scan nodes in this subgraph */
					spn2 = splay_tree_min(sg->sp_nl);
					while (spn2) {
						un = (struct unode *)spn2->value;
						if (un->x0 < sg->aminx) {
							sg->aminx = un->x0;
						}

						if (un->y1 < sg->aminy) {
							sg->aminy = un->y1;
						}

						if ((un->x0 + un->bbx) > sg->amaxx) {
							sg->amaxx = (un->x0 + un->bbx);
						}

						if ((un->y1 + un->bby) > sg->amaxy) {
							sg->amaxy = (un->y1 + un->bby);
						}

						spn2 = splay_tree_successor(sg->sp_nl, spn2->key);
					}
				}
			}

			spn = splay_tree_successor(sp_parsedwsgl, spn->key);
		}
	}

	return;
}

/* */
static int getnodedata_from_rhp_1(int num, int level, int pos, void *data)
{
	struct unode *un = (struct unode *)0;
	un = (struct unode *)data;
	if (un == (struct unode *)0) {
		/* shouldnothappen and set stop signal */
		return (1);
	}

	if (level) {		/* node is at level */
	}

	un->pos = pos;
	un->sp_poe = splay_tree_delete(un->sp_poe);
	un->indegree = 0;
	un->outdegree = 0;
	if (option_ldebug || 0) {
		printf("%s(): node \"%s\" number %d num %d level %d pos %d\n", __FUNCTION__, un->name, un->number, num, level, pos);
	}

	return (0);
}

/* */
static int getnodedata_from_rhp_2(int num, int level, int pos, void *data)
{
	struct unode *un = (struct unode *)0;
	struct drawn *new_drawn = NULL;
	struct ddn *new_ddn = NULL;
	un = (struct unode *)data;
	if (un == (struct unode *)0) {
		/* shouldnothappen and set stop signal */
		return (1);
	}

	if (num) {		/* node has number */
	}
	if (pos) {		/* node is at position */
	}

	/* add in node list */
	new_drawn = drawn_new();
	new_drawn->un = un;	/* node data */
	drawnl_add(new_drawn);
	/* add in layer info */
	new_ddn = ddn_new();
	new_ddn->dn = new_drawn;
	dli_add_node(dlip[level], new_ddn);
	if (option_ldebug || 0) {
		printf("%s(): node \"%s\" number %d num %d level %d pos %d\n", __FUNCTION__, un->name, un->number, num, level, pos);
	}

	return (0);
}

/* copy layouter data into drawing data */
static void static_layouter2draw(void)
{
	splay_tree_node spn = (splay_tree_node) 0;
	int i = 0;
	int count = 0;
	int layer = 0;
	struct drawe *new_drawe = NULL;
	struct dde *new_dde = NULL;
	struct unode *un = NULL;
	struct uedge *ue = (struct uedge *)0;
	int status = 0;
	struct dli *lp = NULL;
	struct ddn *dnptr = NULL;
	/* fresh drawing node edge data */
	dli_clear();
	drawnl_clear();
	drawel_clear();
	/* check for nodes in the layouter */
	if (number_of_nodes == 0) {
		/* nothing todo */
		maxx = 1;
		maxy = 1;
		/* number of nodes+edges in drawing after folding etc. including invisible edges */
		n_drawing_nodes = 0;
		n_drawing_edges = 0;
		return;
	}

	/* number of nodes+edges in drawing after folding etc. including invisible edges */
	n_drawing_nodes = 0;
	n_drawing_edges = 0;
	/* create the draw layer information data */
	dli_nlevels = number_of_layers;
	dlip = mymalloc(dli_nlevels * sizeof(struct dli *), __FUNCTION__, __LINE__);
	for (i = 0; i < dli_nlevels; i++) {
		dlip[i] = dli_new();
	}

	status = 0;
	/* get node data */
	status = rhp_node_foreach(getnodedata_from_rhp_1);
	if (status) {
	}

	for (layer = 0; layer < number_of_layers; layer++) {
		/* set number of nodes in layer information */
		/* get number of nodes in level */
		dlip[layer]->nnodes = (int)rhp_nodes_in_level(layer);
		/* set number of edge crossings in layer information */
		/* calculate crossings at level from 64->32 bit here */
		dlip[layer]->ncross = (int)rhp_current_crossings_at_level(layer);
		/* update total drawing nodes count */
		n_drawing_nodes = n_drawing_nodes + dlip[layer]->nnodes;
	}

	status = 0;
	/* get node data */
	status = rhp_node_foreach(getnodedata_from_rhp_2);
	if (status) {
	}

	n_drawing_edges = 0;
	/* copy edges into rhp layouter */
	spn = splay_tree_min(sp_parsedwel);
	while (spn) {
		ue = (struct uedge *)spn->value;
		if (ue) {

			if (option_testcode || 0) {
				printf("%s(): adding edge number=[e%d] from \"%s\" number=[n%d]->\"%s\" number=[n%d] reversed=%d\n",
				       __FUNCTION__, ue->number, ue->fn->name, ue->fn->number, ue->tn->name, ue->tn->number,
				       ue->bitflags.reversed);
			}

			/* add in edge list */
			new_drawe = drawe_new();
			new_drawe->ue = ue;
			drawel_add(new_drawe);
			/* add in layer info */
			new_dde = dde_new();
			new_dde->de = new_drawe;
			dli_add_edge(dlip[ue->fn->level], new_dde);
			/* add edge in poe list of nodes */
			un = ue->fn;
			/* incr. outdegree */
			un->outdegree = (un->outdegree + 1);
			/* add edge to part-of-edge list of node */
			unode_poe_add(un, ue);
			/* set outgoing edge if dummy node */
			un->dout = ue;
			if (option_testcode || 0) {
				printf("%s(): added node number=[n%d] as outgoing node in edge number=[e%d] reversed=%d\n",
				       __FUNCTION__, un->number, ue->number, ue->bitflags.reversed);
			}

			/* to-node */
			un = ue->tn;
			/* incr. indegree */
			un->indegree = (un->indegree + 1);
			/* add edge to part-of-edge list of node */
			unode_poe_add(un, ue);
			/* set incoming edge of dummy node */
			un->din = ue;
			if (option_testcode || 0) {
				printf("%s(): added node number=[n%d] as incoming node in edge number=[e%d] reversed=%d\n",
				       __FUNCTION__, un->number, ue->number, ue->bitflags.reversed);
			}

			/* update number of edges at level */
			dlip[ue->fn->level]->nedges = (dlip[ue->fn->level]->nedges + 1);
			/* counter shown in status line */
			n_drawing_edges = (n_drawing_edges + 1);
		} else {
			printf("%s(): fixme nil ue\n", __FUNCTION__);
		}

		spn = splay_tree_successor(sp_parsedwel, spn->key);
	}

	/* this does free() all used extra memory only used during layout calculation. */
	rhp_deinit();
	if (option_parsedebug || 0) {
		printf("%s(): finished barycenter reducing %d edge crossings to %d edge crossings\n", __FUNCTION__,
		       (int)current_initial_crossings, (int)current_crossings);
		fflush(stdout);
	}

	/* print the graph internal data situation */
	if (option_testcode || 0) {

		/* scan layers */
		for (i = 0; i < dli_nlevels; i++) {
			/* get level */
			lp = dlip[i];
			/* scan nodes in layer */
			dnptr = lp->nl;
			while (dnptr) {
				/* node at this level */
				un = dnptr->dn->un;
				printf
				    ("%s(): at node number=[n%d] indegree=[d%d] outdegree=[d%d] level=[l%d] pos=[p%d] size=(%d,%d) \"%s\" label=\"%s\"\n",
				     __FUNCTION__, un->number, un->indegree, un->outdegree, un->level, un->pos, un->bbx, un->bby,
				     un->name, un->label);
				/* optional edges connected to this node */
				if (un->sp_poe) {
					count = 1;
					spn = splay_tree_min(un->sp_poe);
					/* scan the part-of-edge list */
					while (spn) {
						ue = (struct uedge *)spn->value;
						printf
						    ("%s():    node number=[n%d] sp_poe(%d) is edge number=[e%d] from \"%s\" number=[n%d]->\"%s\" number=[n%d] reversed=%d\n",
						     __FUNCTION__, un->number, count, ue->number, ue->fn->name, ue->fn->number,
						     ue->tn->name, ue->tn->number, ue->bitflags.reversed);
						count = count + 1;
						spn = splay_tree_successor(un->sp_poe, spn->key);
					}

				}	/* if() */

				dnptr = dnptr->next;
			}	/* while() */

		}		/* for() */
		fflush(stdout);
	}

	/* determine node (x,y) positions and update maxx+maxy */
	layouter2draw_pos();
	return;
}

/***zzzzzz***/

/* copy parsed and folded data into layouter */
static void static_parsed2layouter(void)
{
	char buf[64];
	struct timeval tv;
	pid_t pid;
	splay_tree_node spn = (splay_tree_node) 0;
	struct unode *un = (struct unode *)0;
	struct uedge *ue = (struct uedge *)0;
	int ne = 0;
	int nn = 0;
	int status = 0;
	/* clear vars */
	number_of_nodes = 0;
	number_of_edges = 0;
	number_of_layers = 0;
	current_id = 0;
	/* check if there are working nodes */
	if (splay_tree_has_data(sp_parsedwnl) == 0) {
		/* no data shouldnothappen */
		printf("%s(): fixme no work nodes shouldnothappen\n", __FUNCTION__);
		fflush(stdout);
		return;
	}

	if (option_parsedebug || 0) {
		printf("%s(): starting barycenter, wait ...\n", __FUNCTION__);
		fflush(stdout);
	}

	update_statusline("Barycenter... Wait...");
	/* rebuild nodes-at-levels tables */
	nal_rebuild();
	/* create tmp log filename */
	if (option_testcode || 0) {
		(void)gettimeofday(&tv, NULL);
		pid = getpid();
		memset(buf, 0, 64);
		snprintf(buf, (64 - 1), "tuxsee-%d-%d-%d.rhp.txt", (int)pid, (int)tv.tv_sec, (int)tv.tv_usec);
		rhp_init(buf, option_testcode /* 1 or 2 */ );
		/* use value 2 to get memory logs
		 * rhp_init (buf, 2);
		 */
	} else {
		/* init without log file */
		rhp_init((char *)0, 0);
	}

	/* edge crossings */
	current_initial_crossings = (int64_t) 0;
	current_crossings = (int64_t) 0;
	/* copy nodes into rhp layouter */
	spn = splay_tree_min(sp_parsedwnl);
	nn = 0;
	while (spn) {

		un = (struct unode *)spn->value;
		if (un) {

			/* add node to rhp using number and level */
			status = rhp_addnode((int)un->number, (int)un->level, (void *)un);
			if (status == 0) {
				/* oke status */
				nn = (nn + 1);
			} else {
				/* shouldnothappen but keep on going */
				printf("%s(): adding node failed\n", __FUNCTION__);
				fflush(stdout);
			}
		} else {
			printf("%s(): fixme nil node\n", __FUNCTION__);
		}

		spn = splay_tree_successor(sp_parsedwnl, spn->key);
	}

	/* this are the actual number of nodes in layouter */
	number_of_nodes = nn;
	/* copy edges into rhp layouter */
	spn = splay_tree_min(sp_parsedwel);
	/* refresh count of reversed edges */
	n_input_revedges = 0;
	ne = 0;
	while (spn) {

		ue = (struct uedge *)spn->value;
		if (ue) {
			/* update revcount */
			if (ue->bitflags.reversed) {
				n_input_revedges = n_input_revedges + 1;
			}

			/* add edge to layouter usinge node numbers */
			status = rhp_addedge((int)ue->number, (int)ue->fn->number, (int)ue->tn->number, (void *)ue);
			if (status == 0) {
				ne = (ne + 1);
			} else {
				/* shouldnothappen but keep on going */
				printf("%s(): fixme adding edge failed\n", __FUNCTION__);
				fflush(stdout);
			}
		} else {
			printf("%s(): fixme nil ue\n", __FUNCTION__);
			fflush(stdout);
		}

		spn = splay_tree_successor(sp_parsedwel, spn->key);
	}

	/* this are the actual number of edges in layouter */
	number_of_edges = ne;
	number_of_layers = nlevels;
	if (option_ldebug || 0) {
		printf("%s(): %d nodes, %d edges, %d layers, %d reversed edges\n", __FUNCTION__, nn, ne, nlevels, n_input_revedges);
		fflush(stdout);
	}

	return;
}

/***zz4**/

/* clear the nodes-at-level tables */
static void nal_clear(void)
{
	int i = 0;
	struct dln *nptr = NULL;
	struct dln *nptrtmp = NULL;
	/* no levels is no data */
	if (nal_nlevels == 0) {
		return;
	}

	/* clear all levels */
	for (i = 0; i < nal_nlevels; i++) {
		nptr = nal[i];
		while (nptr) {
			nptrtmp = nptr->next;
			myfree(nptr, __FUNCTION__, __LINE__);
			nptr = NULL;
			nptr = nptrtmp;
		}

	}

	/* clear nal tables itself */
	myfree(nal, __FUNCTION__, __LINE__);
	myfree(nal_end, __FUNCTION__, __LINE__);
	/* clear node count tables */
	myfree(nal_count, __FUNCTION__, __LINE__);
	/* nodes-at-level tables */
	nal = NULL;
	/* nodes-at-level tables */
	nal_end = NULL;
	/* how many levels */
	nal_nlevels = 0;
	/* nodes-at-level number of nodes for every level */
	nal_count = NULL;
	return;
}

/* print nodes at level data */
static void nal_print(void)
{
	int i = 0;
	int nn = 0;
	struct dln *nptr = NULL;
	/* total number of nodes */
	nn = 0;
	for (i = 0; i < nal_nlevels; i++) {
		printf("%s(): level %d of %d levels has %d nodes:\n", __FUNCTION__, i, nal_nlevels, nal_count[i]);
		nn = nn + nal_count[i];
		nptr = nal[i];
		if (nptr) {
			printf("%s(): ", __FUNCTION__);
			while (nptr) {
				printf("\"%s\",", nptr->un->name);
				nptr = nptr->next;
			}

			printf("\n");
		}

	}

	printf("%s(): there are %d nodes in %d levels\n", __FUNCTION__, nn, nal_nlevels);
	fflush(stdout);
	return;
}

/* rebuild nodes-at-levels tables */
static void nal_rebuild(void)
{
	struct dln *new_dln = NULL;
	splay_tree_node spn = (splay_tree_node) 0;
	struct unode *un = (struct unode *)0;
	/* clear old tables if any */
	nal_clear();
	/* how many levels in use */
	nal_nlevels = nlevels;
	/* tables with the nodes for every level */
	nal = mymalloc(nal_nlevels * sizeof(struct dln *), __FUNCTION__, __LINE__);
	nal_end = mymalloc(nal_nlevels * sizeof(struct dln *), __FUNCTION__, __LINE__);
	/* count of number of nodes in every level */
	nal_count = mymalloc(nal_nlevels * sizeof(int), __FUNCTION__, __LINE__);
	spn = splay_tree_min(sp_parsedwnl);
	while (spn) {
		un = (struct unode *)spn->value;
		/* */
		new_dln = dln_new();
		new_dln->un = un;
		/* add node to the tables */
		if (nal_end[un->level] == NULL) {
			/* first entry */
			nal[un->level] = new_dln;
			nal_end[un->level] = new_dln;
		} else {
			nal_end[un->level]->next = new_dln;
			nal_end[un->level] = new_dln;
		}

		/* update number of nodes in level */
		nal_count[un->level] = (nal_count[un->level] + 1);
		spn = splay_tree_successor(sp_parsedwnl, spn->key);
	}

	if (option_ldebug) {
		nal_print();
	}

	return;
}

/***zz5***/

/* clear and free all layouter data malloced and preset to defaults */
static void static_mainl_clear(void)
{

	/* clear all possible malloc'ed */
	nal_clear();
	/* vars */
	number_of_nodes = 0;
	number_of_edges = 0;
	number_of_layers = 0;
	current_id = 0;
	return;
}

/* end */
